/*
 * Copyright (c) 2022. China Mobile (SuZhou) Software Technology Co.,Ltd. All rights reserved.
 * Lakehouse is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

package com.chinamobile.cmss.lakehouse.core.deploy.component.descriptor;

import com.chinamobile.cmss.lakehouse.common.utils.ResourceUtils;
import com.chinamobile.cmss.lakehouse.core.config.ComponentConfiguration;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;

import io.kubernetes.client.openapi.models.V1ConfigMap;
import io.kubernetes.client.openapi.models.V1Deployment;
import io.kubernetes.client.openapi.models.V1Service;
import io.kubernetes.client.openapi.models.V1StatefulSet;
import io.kubernetes.client.util.Yaml;

public abstract class ComponentDescriptor {

    /**
     * build config map
     *
     * @param config component config
     * @return
     * @throws IOException
     */
    public abstract Optional<List<V1ConfigMap>> buildConfigMap(ComponentConfiguration config)
        throws IOException;

    /**
     * build service
     *
     * @param config component config
     * @return
     * @throws IOException
     */
    public abstract Optional<List<V1Service>> buildService(ComponentConfiguration config)
        throws IOException;

    /**
     * build stateful set
     *
     * @param config component config
     * @return
     * @throws IOException
     */
    public abstract Optional<V1StatefulSet> buildStatefulSet(ComponentConfiguration config)
        throws IOException;

    /**
     * build deployment
     *
     * @param config component config
     * @return
     * @throws IOException
     */
    public abstract Optional<V1Deployment> buildDeployment(ComponentConfiguration config)
        throws IOException;

    /**
     * k8s internal service
     *
     * @param namespace namespace name
     * @return
     */
    public abstract String k8sInternalService(String namespace);

    /**
     * get k8s external service
     *
     * @param namespace namespace name
     * @return
     */
    public abstract String k8sExternalService(String namespace);

    /**
     * update statefulset resources
     */
    protected void updateStatefulSetResources(V1StatefulSet statefulSet, double cpuOverScore,
                                              double vcores, double memoryOfGb) {
        statefulSet.getSpec().getTemplate().getSpec().getContainers().get(0)
            .resources(ResourceUtils.resourceRequirements(cpuOverScore, vcores, memoryOfGb));
    }

    /**
     * update statefulset args
     */
    protected void updateStatefulSetArgs(V1StatefulSet statefulSet, String newArgs) {
        List<String> newArgsList = new ArrayList<>(1);
        newArgsList.add(newArgs);
        statefulSet.getSpec().getTemplate().getSpec().getContainers().get(0).args(newArgsList);
    }

    /**
     * parse ConfigMap from yaml
     */
    protected V1ConfigMap parseConfigMap(String yaml) throws IOException {
        List<Object> objects = Yaml.loadAll(yaml);
        for (Object obj : objects) {
            Class<?> aClass = obj.getClass();
            if (aClass.isAssignableFrom(V1ConfigMap.class)) {
                return (V1ConfigMap) obj;
            }
        }
        return null;
    }

    /**
     * parse V1Service from yaml
     */
    protected V1Service parseService(String yaml) throws IOException {
        List<Object> objects = Yaml.loadAll(yaml);
        for (Object obj : objects) {
            Class<?> aClass = obj.getClass();
            if (aClass.isAssignableFrom(V1Service.class)) {
                return (V1Service) obj;
            }
        }
        return null;
    }

    /**
     * parse StatefulSet from yaml
     */
    protected V1StatefulSet parseStatefulSet(String yaml) throws IOException {
        List<Object> objects = Yaml.loadAll(yaml);
        for (Object obj : objects) {
            Class<?> aClass = obj.getClass();
            if (aClass.isAssignableFrom(V1StatefulSet.class)) {
                return (V1StatefulSet) obj;
            }
        }
        return null;
    }

    /**
     * parse StatefulSet from yaml
     */
    protected V1Deployment parseDeployment(String yaml) throws IOException {
        List<Object> objects = Yaml.loadAll(yaml);
        for (Object obj : objects) {
            Class<?> aClass = obj.getClass();
            if (aClass.isAssignableFrom(V1Deployment.class)) {
                return (V1Deployment) obj;
            }
        }
        return null;
    }

}